<?php

namespace App\Exceptions;

use Carbon\Exceptions\InvalidDateException;
use Exception;
use GuzzleHttp\Exception\ClientException;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ServerException;
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Response;
use Illuminate\Routing\UrlGenerator;
use Illuminate\Support\MessageBag;
use Illuminate\Validation\ValidationException;
use function Psy\debug;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class Handler extends ExceptionHandler
{
    /**
     * A list of the exception types that are not reported.
     *
     * @var array
     */
    protected $dontReport = [
        //
    ];

    /**
     * A list of the inputs that are never flashed for validation exceptions.
     *
     * @var array
     */
    protected $dontFlash = [
        'password',
        'password_confirmation',
    ];

    /**
     * Report or log an exception.
     *
     * This is a great spot to send exceptions to Sentry, Bugsnag, etc.
     *
     * @param  \Exception $exception
     * @return void
     */
    public function report(Exception $exception)
    {
        parent::report($exception);
    }

    /**
     * Render an exception into an HTTP response.
     * @todo 暂时400错误全部跳404,500错误直接跳500
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Exception $exception
     * @return \Illuminate\Http\Response
     */
    public function render($request, Exception $exception)
    {
        $debug = config('app.debug');
        if ('foradmin' == array_get(explode('/', request()->path()), '0')) { //后台登录模块
            $error_404 = 'admin.error.404';
            $error_500 = 'admin.error.500';
        } else {
            $error_404 = 'web.error.404';
            $error_500 = 'web.error.500';
        }

        if ($exception instanceof NoTLoginException || $exception->getPrevious() instanceof NoTLoginException) {//未登录异常
            $e = $exception;
            $e = $exception->getPrevious() instanceof NoTLoginException ? $exception->getPrevious() : $exception;
            if ($request->ajax()) {
                return new JsonResponse(['code' => $e->getCode(), 'message' => $e->getMessage(), 'data' => null]);
            } else {
                if ('foradmin' == array_get(explode('/', request()->path()), '0')) { //后台登录模块
                    return redirect()->to(route('admin.login'));
                } else {
                    //@to do 前端登录
                }
            }
        }

        //GuzzleHttp - API请求异常捕获
        if ($exception instanceof ClientException) {    //400级别
            if ($request->ajax()) {
                return new JsonResponse(['HttpCode' => $exception->getResponse()->getStatusCode(), 'message' => $exception->getResponse()->getBody()->getContents(), 'code' => 1], 404);
            } else {
                switch ($exception->getCode()) {
                    case 422://表单验证失败
                        $ret = json_decode($exception->getResponse()->getBody()->getContents(), 1);
                        $errors = new MessageBag((array)array_get($ret, 'message', []));
                        $request->session()->flash('errors', $errors);
                        $request->flash();
                        return redirect(\URL::previous());
                        break;
                    case 404:
                        if ($debug) {
                            $content = str_replace('Sorry,', '<<< Error of API >>> Sorry,', $exception->getResponse()->getBody()->getContents());
                            $content = str_replace('Whoops,', '<<< Error of API >>> Whoops,', $content);
                            print_r($content);
                            exit;
                        } else {
                            return redirect()->to(route($error_404));
                        }
                    default:
                        if ($debug) {
                            $content = str_replace('Sorry, the page', '<<< Error of API >>> Sorry,', $exception->getResponse()->getBody()->getContents());
                            print_r($content);
                            exit;
                        } else {
                            return redirect()->to(route($error_404));
                        }
                }
            }
        }
        if ($exception instanceof ServerException) {    //500级别
            if ($request->ajax()) {
                return new JsonResponse(['HttpCode' => $exception->getResponse()->getStatusCode(), 'message' => $exception->getResponse()->getBody()->getContents(), 'code' => 1], 500);
            } elseif ($debug) {
                $content = str_replace('Whoops,', '<<< Error of API >>> Whoops,', $exception->getResponse()->getBody()->getContents());
                print_r($content);
                exit;
            } else {
                return redirect()->to(route($error_500));
            }
        }

        //自身异常处理
        if ($exception instanceof ValidationException) {//表单验证异常
            if ($request->ajax() || $request->wantsJson()) {
                return new JsonResponse($exception->errors(), 422);
            }
            return redirect()->to(\URL::previous())
                ->withInput($request->input())
                ->withErrors($exception->errors());
        } elseif ($exception instanceof NotFoundHttpException && !$debug) {
            if ($request->ajax()) {
                return new JsonResponse(['HttpCode' => 404], 404);
            } else {
                return redirect()->to(route($error_404));
            }
        } elseif (!$debug) {  //其它未知情况统一报500错误
            if ($request->ajax()) {
                return new JsonResponse(['HttpCode' => 500], 500);
            } else {
                return redirect()->to(route($error_500));
            }
        }

        return parent::render($request, $exception);
    }
}
